package cn.com.chengmandian.bike.service.impl;

import cn.com.chengmandian.bike.model.*;
import cn.com.chengmandian.bike.mapper.EbDepositRecordMapper;
import cn.com.chengmandian.bike.service.*;
import cn.com.chengmandian.bike.utils.AliPayUtil;
import cn.com.chengmandian.bike.utils.WxPayUtil;
import cn.com.chengmandian.core.common.constants.CommonConstant;
import cn.com.chengmandian.core.redis.service.RedisService;
import cn.com.chengmandian.core.web.exceptions.BadResponseException;
import cn.com.chengmandian.core.web.pojo.AgentInfo;
import cn.com.chengmandian.core.web.pojo.AjaxResult;
import cn.com.chengmandian.core.web.pojo.LoginUser;
import cn.com.chengmandian.core.web.utils.SpringContextUtil;
import cn.com.chengmandian.service.bike.BikePayClient;
import cn.com.chengmandian.service.bike.constants.*;
import cn.com.chengmandian.service.bike.form.BikeRefundForm;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.Map;

/**
 * <p>
 * 电单车运营-押金记录 服务实现类
 * </p>
 *
 * @author AutoGenerator
 * @since 2023-11-16
 */
@Service
public class EbDepositRecordServiceImpl extends ServiceImpl<EbDepositRecordMapper, EbDepositRecord> implements IEbDepositRecordService {

    @Autowired
    private RedisService redisService;

    @Autowired
    private IEbMemberPayService memberPayService;

    @Autowired
    private IEbRefundInfoService refundInfoService;

    @Autowired
    private IEbMemberWalletService memberWalletService;

    @Autowired
    private IEbMemberInfoService memberInfoService;

    @Autowired
    private IEbAgentInfoService agentInfoService;

    @Autowired
    private IEbPayAccountService payAccountService;

    @Autowired
    private BikePayClient bikePayClient;

    @Override
    public EbDepositRecord getByMember(Integer memberId) {
        return this.getOne(new LambdaQueryWrapper<EbDepositRecord>()
                .eq(EbDepositRecord::getMemberId, memberId)
                .eq(EbDepositRecord::getStatus, CommonConstant.ONE)
                .orderByDesc(EbDepositRecord::getId)
                .last("limit 0,1"));
    }

    @Override
    public void createRecord(Integer memberId, BigDecimal money, Integer payId) {
        EbDepositRecord depositRecord = new EbDepositRecord();
        depositRecord.setMemberId(memberId);
        depositRecord.setMoney(money);
        depositRecord.setPayId(payId);
        depositRecord.setStatus(CommonConstant.ONE);
        depositRecord.setRefundType(DepositRefundTypeEnum.NO.getCode());
        this.save(depositRecord);
    }

    @Override
    public void refund(EbDepositRecord depositRecord, String refundRemark, AgentInfo agentInfo, LoginUser loginUser) {
        String key = SpringContextUtil.getAppName().toUpperCase() + ":BIKE:REFUND:RIDE:DEPOSIT:" + depositRecord.getId();
        try {
            if (redisService.hasKey(key)) {
                throw new BadResponseException("该押金正在退款中,请稍等....");
            }
            redisService.set(key, depositRecord.getId(), 3);

            // 支付记录
            EbMemberPay ebMemberPay = memberPayService.getById(depositRecord.getPayId());
            Assert.notNull(ebMemberPay, "支付记录信息不存在");
            Assert.isTrue(ebMemberPay.getMoney().compareTo(BigDecimal.ZERO) > 0, "金额不支持退款!");

            String notifyUrl = "http://"+ agentInfo.getDomain() + "/api/v1/bikeuser/notify";
            if (ebMemberPay.getPayChannel().equals(PayChannelEnum.WALLET.getCode())) {
                // 生成退款支付记录
                EbRefundInfo ebRefundInfo = refundInfoService.createRefund(ebMemberPay.getAreaId(),ebMemberPay.getMemberId(), depositRecord.getId(), ebMemberPay.getId(), ebMemberPay.getFeeRatio(), depositRecord.getMoney(), RefundBusinessTypeEnum.YAJIN, RefundChannelEnum.MONEY, refundRemark,loginUser);
                memberWalletService.refundMoney(ebMemberPay.getAreaId(), ebMemberPay.getMemberId(), MemberMoneyBusinessTypeEnum.DEPOSIT_REFUND, depositRecord.getId(), depositRecord.getMoney(),BigDecimal.ZERO);
                this.refundSuccess(ebRefundInfo);
            } else if (ebMemberPay.getPayChannel().equals(PayChannelEnum.WXPAY.getCode())) {
                // 生成退款支付记录
                EbRefundInfo ebRefundInfo = refundInfoService.createRefund(ebMemberPay.getAreaId(),ebMemberPay.getMemberId(), depositRecord.getId(), ebMemberPay.getId(), ebMemberPay.getFeeRatio(), depositRecord.getMoney(), RefundBusinessTypeEnum.YAJIN, RefundChannelEnum.WX, refundRemark,loginUser);

                EbMemberInfo ebMemberInfo = memberInfoService.getById(depositRecord.getMemberId());
                EbAgentInfo info = agentInfoService.getById(agentInfo.getId());
                if (info.getPayAccountId() != null) {
                    EbPayAccount payAccount = payAccountService.getPayAccount(info.getPayAccountId(), depositRecord.getMemberId());
                    if (payAccount != null) {
                        BikeRefundForm refundForm = new BikeRefundForm();
                        refundForm.setBusinessType(RefundBusinessTypeEnum.YAJIN);
                        refundForm.setMemberPayId(ebMemberPay.getId());
                        refundForm.setMoney(ebRefundInfo.getMoney());
                        refundForm.setRefundNo(ebRefundInfo.getRefundNo());
                        refundForm.setAlipayUserId(ebMemberInfo.getAlipayUserId());
                        refundForm.setAlipayOpenId(ebMemberInfo.getAlipayOpenId());
                        AjaxResult result = bikePayClient.refund(ebMemberPay.getAgentId(), refundForm);
                        Assert.isTrue(result.isSuccess(), result.getMessage());
                        return;
                    }
                }

                try {
                    WxPayUtil.refund(
                            agentInfo.getWxMchId(),
                            ebRefundInfo.getRefundNo(),
                            ebMemberPay.getPayNo(),
                            "押金退款",
                            ebRefundInfo.getMoney(),
                            ebMemberPay.getMoney(),
                            agentInfo.getWxKeyPath(),
                            agentInfo.getWxCertPath(),
                            notifyUrl + "/wx/refund/" + agentInfo.getId());
                } catch (Exception ex) {
                    log.error("微信退款失败", ex);
                    throw new BadResponseException("微信退款失败:" + ex.getMessage());
                }
            } else if (ebMemberPay.getPayChannel().equals(PayChannelEnum.ALIPAY.getCode())) {
                // 生成退款支付记录
                EbRefundInfo ebRefundInfo = refundInfoService.createRefund(ebMemberPay.getAreaId(),ebMemberPay.getMemberId(), depositRecord.getId(), ebMemberPay.getId(), ebMemberPay.getFeeRatio(), depositRecord.getMoney(), RefundBusinessTypeEnum.YAJIN, RefundChannelEnum.ALI, refundRemark,loginUser);
                EbMemberInfo ebMemberInfo = memberInfoService.getById(depositRecord.getMemberId());
                EbAgentInfo info = agentInfoService.getById(agentInfo.getId());
                if (info.getPayAccountId() != null) {
                    EbPayAccount payAccount = payAccountService.getPayAccount(info.getPayAccountId(), depositRecord.getMemberId());
                    if (payAccount != null) {
                        BikeRefundForm refundForm = new BikeRefundForm();
                        refundForm.setBusinessType(RefundBusinessTypeEnum.YAJIN);
                        refundForm.setMemberPayId(ebMemberPay.getId());
                        refundForm.setMoney(ebRefundInfo.getMoney());
                        refundForm.setRefundNo(ebRefundInfo.getRefundNo());
                        refundForm.setAlipayUserId(ebMemberInfo.getAlipayUserId());
                        refundForm.setAlipayOpenId(ebMemberInfo.getAlipayOpenId());
                        AjaxResult result = bikePayClient.refund(ebMemberPay.getAgentId(), refundForm);
                        Assert.isTrue(result.isSuccess(), result.getMessage());
                        return;
                    }
                }
                try {
                    Map<String, String> res = AliPayUtil.getTradeRefundRequestParam(
                            agentInfo.getAliMiniAppid(),
                            ebMemberInfo.getAlipayUserId(),
                            ebMemberInfo.getAlipayOpenId(),
                            "押金退款",
                            ebMemberPay.getPayNo(),
                            ebRefundInfo.getRefundNo(),
                            ebRefundInfo.getMoney(),
                            agentInfo.getAliPayPrivateKey(),
                            agentInfo.getAliPayCertPath(),
                            agentInfo.getAliPayPublicCertPath(),
                            agentInfo.getAliPayRootCertPath());
                    ebRefundInfo.setChannelNo(res.get("trade_no"));
                    this.refundSuccess(ebRefundInfo);
                } catch (Exception ex) {
                    log.error("支付宝退款失败", ex);
                    throw new BadResponseException("支付宝退款失败:" + ex.getMessage());
                }
            }
        }catch (Exception ex){
            redisService.del(key);
            throw new BadResponseException(ex.getMessage());
        }
    }

    @Override
    public void refundSuccess(EbRefundInfo ebRefundInfo) {
        EbDepositRecord depositRecord = this.getById(ebRefundInfo.getBusinessId());

        this.update(new LambdaUpdateWrapper<EbDepositRecord>()
                .set(EbDepositRecord::getRefundRemark, ebRefundInfo.getReason())
                .set(EbDepositRecord::getRefundTime, DateUtil.date())
                .set(EbDepositRecord::getRefundType, DepositRefundTypeEnum.ORI_ROAD.getCode())
                .set(EbDepositRecord::getStatus, CommonConstant.TWO)
                .eq(EbDepositRecord::getId, depositRecord.getId()));

        memberInfoService.update(new LambdaUpdateWrapper<EbMemberInfo>()
                .set(EbMemberInfo::getIsDeposit, CommonConstant.ZERO)
                .set(EbMemberInfo::getDepositMoney, null)
                .eq(EbMemberInfo::getId, depositRecord.getMemberId()));
    }
}
